package com.apes.framework.util;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.SpringManager;
import org.apache.commons.beanutils.BeanUtils;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import static java.text.MessageFormat.format;

/**
 * 功能：普通工具类
 *
 * @author xul
 * @create 2017-12-02 16:28
 */
public class Tools {

    private static Mapper getMapper() {
        return SpringManager.getBean(DozerBeanMapper.class);
    }

    /**
     * 此方法检查一个字符串是否为空。 <p>
     *
     * @param s String - 检查的对象字符串。<p>
     * @return boolean - 如果是空串，则返回true，否则返回false。
     */
    public static boolean isNull(String s) { //检查传入字符串是否为空
        return (s == null) || s.trim().equals("");
    }

    public static boolean isNull(Object o) {
        return (o == null) || String.valueOf(o).equals("");
    }


    /**
     * Converts a JavaBean to a mapped.
     *
     * @param bean JavaBean to convert
     * @return mapped converted
     */
    public static final Map<String, Object> toMap(Object bean) {
        try {
            Map<String, Object> returnMap = new HashMap<String, Object>();
            BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (!propertyName.equals("class")) {
                    Method readMethod = descriptor.getReadMethod();
                    Object result = readMethod.invoke(bean, new Object[0]);
                    if (result != null) {
                        returnMap.put(propertyName, result);
                    } else {
                        returnMap.put(propertyName, "");
                    }
                }
            }
            return returnMap;
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

//    public static final <T> T toBean(Class<?> type, Map<String, ? extends Object> mapped){
//        try {
//            BeanInfo beanInfo = Introspector.getBeanInfo(type);
//            Object obj = type.newInstance();
//            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//            for (int i = 0; i < propertyDescriptors.length; i++) {
//                PropertyDescriptor descriptor = propertyDescriptors[i];
//                String propertyName = descriptor.getName();
//                if (mapped.containsKey(propertyName)) {
//                    Object value = mapped.get(propertyName);
//                    Object[] args = new Object[1];
//                    args[0] = value;
//                    descriptor.getWriteMethod().invoke(obj, args);
//                }
//            }
//            return (T) obj;
//        } catch (IntrospectionException e) {
//            throw new RuntimeException(e);
//        } catch (IllegalAccessException e) {
//            throw new RuntimeException(e);
//        } catch (InstantiationException e) {
//            throw new RuntimeException(e);
//        } catch (InvocationTargetException e) {
//            throw new RuntimeException(e);
//        }
//    }

    //@Deprecated
    public static <T> T toBean(Class<T> type, Map<String, ? extends Object> row) {
        try {
            T bean = type.newInstance();
            for (Map.Entry<String, ?> entry : row.entrySet()) {
                BeanUtils.setProperty(bean, entry.getKey(), entry.getValue());
            }
            return bean;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 深度映射(Deep Mapping) (Object - Object)
     * 构造新的destinationClass实例对象，通过source对象中的字段内容
     * 映射到destinationClass实例对象中，并返回新的destinationClass实例对象。
     *
     * @param source 源数据对象
     * @param type   要构造新的实例对象Class
     */
    public static <T> T map(Object source, Class<T> type) {
        //Mapper mapper = new DozerBeanMapper();
        try {
            return getMapper().map(source, type);
        } catch (Exception e) {
            throw new RuntimeException(getThrowable(e));
        }
    }

    public static Throwable getThrowable(Throwable e) {
        Throwable throwable = e.getCause();
        if (throwable == null) return e;
        return getThrowable(throwable);
    }

    public static StackTraceElement getFirstStackTrace(Throwable e) {
        Throwable throwable = Tools.getThrowable(e);
        if (throwable == null) {
            return null;
        }
        return Arrays.stream(throwable.getStackTrace()).findFirst().orElse(null);
    }

    public static String getAllStackTrace(Throwable e) {
        Throwable throwable = Tools.getThrowable(e);
        if (throwable == null) {
            return null;
        }
        StringBuffer sb = new StringBuffer();
        Arrays.stream(throwable.getStackTrace()).forEach(stackTraceElement -> {
            if (sb.length() > 0) {
                sb.append("\n");
            }
            sb.append(stackTraceElement.toString());
        });
        return sb.toString();
    }

    public static String formatStackTrace() {
        StringBuffer sb = new StringBuffer();
        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
            if (sb.length() > 0) {
                sb.append("\n");
            }
            sb.append(format("{0}.{1}({2}:{3}) ", e.getClassName(), e.getMethodName(), e.getFileName(), e.getLineNumber()));
        }
        return sb.toString();
    }

    public static String formatStackTrace(String filter) {
        StringBuffer sb = new StringBuffer();
        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
            if(!e.getClassName().startsWith(filter)){
                continue;
            }
            if (sb.length() > 0) {
                sb.append("\n");
            }
            sb.append(format("{0}.{1}({2}:{3}) ", e.getClassName(), e.getMethodName(), e.getFileName(), e.getLineNumber()));
        }
        return sb.toString();
    }

    public static <T> List<T> map(Collection source, Class<T> type) {
//        Mapper mapper = new DozerBeanMapper();
        List rows = new ArrayList();
        for (Iterator iterator = source.iterator(); iterator.hasNext(); ) {
            Object sourceObject = iterator.next();
            Object destinationObject = getMapper().map(sourceObject, type);
            rows.add(destinationObject);
        }
        return rows;
    }

    /**
     * 将对象source的所有属性值拷贝到对象destination中.
     *
     * @param source 对象source
     * @param target 对象target
     */
    public static void map(Object source, Object target) {
//        Mapper mapper = new DozerBeanMapper();
        getMapper().map(source, target);
    }


//    public static <T> Map<String, T> toMap(Object target) {
//        return toMap(target,false);
//    }

//    /**
//     * 将目标对象的所有属性转换成Map对象
//     *
//     * @param target 目标对象
//     * @param ignoreParent 是否忽略父类的属性
//     *
//     * @return Map
//     */
//    public static <T> Map<String, T> toMap(Object target,boolean ignoreParent) {
//        return toMap(target,ignoreParent,false);
//    }
//
//    /**
//     * 将目标对象的所有属性转换成Map对象
//     *
//     * @param target 目标对象
//     * @param ignoreParent 是否忽略父类的属性
//     * @param ignoreEmptyValue 是否不把空值添加到Map中
//     *
//     * @return Map
//     */
//    public static <T> Map<String, T> toMap(Object target,boolean ignoreParent,boolean ignoreEmptyValue) {
//        return toMap(target,ignoreParent,ignoreEmptyValue,new String[0]);
//    }
//
//    /**
//     * 将目标对象的所有属性转换成Map对象
//     *
//     * @param target 目标对象
//     * @param ignoreParent 是否忽略父类的属性
//     * @param ignoreEmptyValue 是否不把空值添加到Map中
//     * @param ignoreProperties 不需要添加到Map的属性名
//     */
//    public static <T> Map<String, T> toMap(Object target,boolean ignoreParent,boolean ignoreEmptyValue,String... ignoreProperties) {
//        Map<String, T> mapped = new HashMap<String, T>();
//
//        List<Field> fields = Arrays.asList(target.getClass().getDeclaredFields());
//
//        for (Iterator<Field> it = fields.iterator(); it.hasNext();) {
//            Field field = it.next();
//            T value = null;
//
//            try {
//                value = (T) field.get(target);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//
//            if (ignoreEmptyValue
//                    && ((value == null || value.toString().equals(""))
//                    || (value instanceof Collection && ((Collection<?>) value).isEmpty())
//                    || (value instanceof Map && ((Map<?,?>)value).isEmpty()))) {
//                continue;
//            }
//
//            boolean flag = true;
//            String key = field.getName();
//
//            for (String ignoreProperty:ignoreProperties) {
//                if (key.equals(ignoreProperty)) {
//                    flag = false;
//                    break;
//                }
//            }
//
//            if (flag) {
//                mapped.put(key, value);
//            }
//        }
//
//        return mapped;
//    }


    /**
     * 两个Bean之间属性对拷
     *
     * @param <T>
     * @param dest   现将要设置新值的对象
     * @param source 源数据对象
     */
    //@Deprecated
    public static <T> void beanConvert(T dest, T source) {
        try {
            BeanUtils.copyProperties(dest, source);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public static String replace(String s) {
        return SpringManager.getBean(PropertiesUtils.class).replace(s);
    }


    public static Object getJO(String jsonStr) {
        Object data = jsonStr;
        if (((String) data).startsWith("[")) {
            return JSONArray.parseArray((String) data);
        } else if (((String) data).startsWith("{")) {
            return JSONObject.parseObject((String) data);
        } else {
            throw new RuntimeException("输入数据格式不正确。");
        }
    }

    /**
     * 功能：数据类型转换
     *
     * @param type
     * @param value
     * @return
     */
    public static Object convert(String type, Object value) {
        if (type == null) {
            return value;
        }
        Object result;
        String s = String.valueOf(value);
        if (type.equalsIgnoreCase("string")) {
            if (value instanceof Object[]) {
                result = JSONArray.toJSONString(value);
            } else {
                result = s;
            }
        } else if (type.equalsIgnoreCase("int")) {
            if (s.length() == 0) {
                result = 0;
            } else {
                result = Integer.parseInt(s);
            }
        } else if (type.equalsIgnoreCase("long")) {
            if (s.length() == 0) {
                result = 0;
            } else {
                result = Long.parseLong(s);
            }
        } else if (type.equalsIgnoreCase("double")) {
            if (s.length() == 0) {
                result = 0;
            } else {
                result = Double.parseDouble(s);
            }
        } else if (type.equalsIgnoreCase("date") || type.equalsIgnoreCase("dateTime")) {
            if (s.length() == 0) {
                result = String.valueOf("");
            } else {
                if (s.length() < 11) {
                    result = DateUtil.parse(s);
                } else {
                    result = DateUtil.parseTimestamp(s);
                }
            }
        } else if (type.equalsIgnoreCase("boolean")) {
            if (s.length() == 0) {
                result = false;
            } else {
                if (s.equalsIgnoreCase("FALSE") || s.equals("0")) result = false;
                else if (s.equalsIgnoreCase("TRUE") || s.equals("1")) result = true;
                else result = false;
            }
        } else if (type.equalsIgnoreCase("array")) {
            if (s.length() == 0) {
                result = new JSONArray();
            } else {
                result = new JSONArray();
                Arrays.stream(s.split(",")).forEach(str -> ((JSONArray) result).add(str.trim()));
            }
        } else {
            result = value;
        }
        return result;
    }

    /**
     * 将参数类型列表转为字符串
     *
     * @param parameterTypes 参数类型列表
     * @return
     */
    public static String getParameterTypes(Class<?>[] parameterTypes) {
        StringBuffer sb = new StringBuffer();
        for (Class<?> clazz : parameterTypes) {
            if (sb.length() > 0) {
                sb.append(",");
            }
            sb.append(clazz.getSimpleName());
        }
        return sb.toString();
    }
}
